use std::collections::HashSet;
use chrono::{Local};
use gloo::timers::callback::Timeout;
use yew::{Callback};
use crate::db::pojo::pojo::{ImConfig, ImDepartment, ImGroup, ImModule, ImSession, ImUser};
use crate::db::service::im_config_service::{save_configs};
use crate::db::service::im_department_service::save_departments;
use crate::db::service::im_group_service::ImGroupService;
use crate::db::service::im_module_service::ImModuleService;
use crate::db::service::im_session_service::ImSessionService;
use crate::db::service::im_user_service::ImUserService;
use crate::business::app_state::{AppState};
use crate::business::service::save_message_service::SaveMessageService;
use crate::business::websocket::dto::im_base_dto::{ConfigPullReq, ModulePullReq};
use crate::business::websocket::dto::im_department_dto::{DepartmentInfoListReq};
use crate::business::websocket::dto::im_group_dto::{GroupInfoListReq, GroupType};
use crate::business::websocket::dto::im_session_dto::{SessionPullReq, SessionType};
use crate::business::websocket::dto::im_message_dto::{MessageObject, MessagePullBySessionIdsReq};
use crate::business::websocket::dto::user_dto::{TerminalType, UserInfoListReq};
use crate::business::websocket::receive_send_handle::ImReceiveSendHandleMsg;
use crate::business::websocket::send_data_router::{RpcRequest, RpcResponse};
use crate::business::websocket::service::pull_end_callback::PullEndCallback;
use crate::business::websocket::service::syn_data_service::SynDataConfig;
use crate::business::websocket::websocket_view::ImWebSocketStatus;

pub fn syn_configs(syn_data_config: SynDataConfig<ImConfig>, pull_end_callback: PullEndCallback<ImConfig>) {
    let websocket_status = syn_data_config.app_state.websocket_status.clone();
    let page_size = 100;

    log::info!("syn configs websocket_status: {:?}", websocket_status);

    let start_server_name = match &syn_data_config.lasted_data {
        None => { None }
        Some(config) => { Some(config.name.clone()) }
    };
    let config_pull_req = ConfigPullReq {
        page_size,
        start_date: syn_data_config.start_time.clone(),
        start_server_name,
        create_date_time: Local::now(),
        local_seq: "".to_string(),
    };

    log::info!("load configs begin, {}", syn_data_config.app_state.receive_send_handle.is_some());

    let pull_end_callback_clone = pull_end_callback.clone();
    let user_id = syn_data_config.user_id.clone();
    let syn_data_config_clone = syn_data_config.clone();

    let callback = Callback::from(move |response: RpcResponse| {
        log::info!("load configs success, data: {:?}", response);

        let user_id_clone = user_id.clone();
        if let RpcResponse::PullConfigsResponse(result) = response {
            match result {
                Ok(config_list_item) => {
                    let mut im_configs = config_list_item.config_items.into_iter().map(|config_item| { config_item.into() }).collect::<Vec<ImConfig>>();
                    save_configs(user_id_clone, &mut im_configs);

                    let syn_data_config_clone2 = syn_data_config_clone.clone();
                    let pull_end_callback_clone2 = pull_end_callback_clone.clone();

                    let is_end = im_configs.len() < page_size;
                    log::info!("im_configs pull is end: {:?}", is_end);
                    let lasted = im_configs.last();
                    let lasted1 = match lasted {
                        None => {None}
                        Some(value) => {
                            let t = value.clone();
                            Some(t)
                        }
                    };

                    let new_syn_data_config = syn_data_config_clone2.copy2(lasted1, is_end);
                    Timeout::new(100, move || {
                        pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                    }).forget();
                }
                Err(_) => {}
            }
        }
        log::info!("load configs success, and save success");
    });

    log::info!("load configs begin2, {}", syn_data_config.app_state.receive_send_handle.is_some());
    let websocket_handle = syn_data_config.app_state.receive_send_handle.clone();
    log::info!("load configs begin21, {}", websocket_handle.is_some());
    if let Some(websocket_handle) = websocket_handle {
        log::info!("load configs begin22");
        websocket_handle.dispatch(ImReceiveSendHandleMsg::Request(RpcRequest::PullConfigs(config_pull_req), callback));
    } else {
        log::info!("no websocket handle");
    }
    log::info!("load configs begin3, {}", syn_data_config.app_state.receive_send_handle.is_some());
}

pub fn syn_departments(syn_data_config: SynDataConfig<ImDepartment>, pull_end_callback: PullEndCallback<ImDepartment>) {
    let page_size = 100;
    let start_org_code = match &syn_data_config.lasted_data {
        None => { None }
        Some(department) => { Some(department.code.clone()) }
    };
    let department_info_list_req = DepartmentInfoListReq {
        start_org_code,
        page_size,
        start_date: syn_data_config.start_time.clone(),
        is_latest_changed: true,
        create_date_time: Local::now(),
        local_seq: "".to_string(),
    };

    let pull_end_callback_clone = pull_end_callback.clone();
    let syn_data_config_clone = syn_data_config.clone();

    let user_id = syn_data_config.user_id.clone();
    let callback = Callback::from(move |response: RpcResponse| {
        log::info!("load departments success, data: {:?}", response);

        let syn_data_config_clone2 = syn_data_config_clone.clone();
        let pull_end_callback_clone2 = pull_end_callback_clone.clone();
        let user_id_clone = user_id.clone();

        if let RpcResponse::PullDepartmentsResponse(result) = response {
            match result {
                Ok(department_info_list_item) => {
                    let mut im_departments = department_info_list_item.department_info_item_list.into_iter().map(|department_info_item| {department_info_item.into()}).collect::<Vec<ImDepartment>>();
                    let is_end = im_departments.len() != 100;
                    let lasted_department = im_departments.last();
                    let lasted : Option<ImDepartment> = match lasted_department {
                        None => {None}
                        Some(department) => {Some(department.clone())}
                    };
                    for department_info in &mut im_departments {
                        department_info.current_user_id = "test00100".to_string();
                    }
                    save_departments(user_id_clone, &mut im_departments);
                    log::info!("load departments success, and save success");

                    let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);
                    Timeout::new(100, move || {
                        pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                    }).forget();
                }
                Err(_) => {}
            }
        }
    });

    send_data(syn_data_config.app_state.clone(), RpcRequest::PullDepartments(department_info_list_req), callback);
}

pub fn syn_users(syn_data_config: SynDataConfig<ImUser>, pull_end_callback: PullEndCallback<ImUser>) {
    let page_size : usize = 200;
    let start_user_id = match &syn_data_config.lasted_data {
        None => {None}
        Some(value) => {
            log::info!("syn users, start_user_id: {:?}", &value.user_id);
            Some(value.user_id.clone())
        }
    };

    let websocket_status = syn_data_config.app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let user_info_list_req = UserInfoListReq {
            create_date_time: Local::now(),
            local_seq: "".to_string(),
            start_user_id,
            page_size: page_size as u32,
            start_date: syn_data_config.start_time.clone(),
            is_latest_change: true,
        };

        log::info!("begin load users, {}", syn_data_config.app_state.receive_send_handle.is_some());

        let syn_data_config_clone = syn_data_config.clone();
        let pull_end_callback_clone = pull_end_callback.clone();

        let callback = Callback::from(move |response: RpcResponse| {
            let pull_end_callback_clone2 = pull_end_callback_clone.clone();
            let syn_data_config_clone2 = syn_data_config_clone.clone();

            if let RpcResponse::PullUsersResponse(result) = response {
                match result {
                    Ok(user_info_item_list) => {
                        let mut im_users = user_info_item_list.user_info_item_list.into_iter().map(|user_info_item| {user_info_item.into()}).collect::<Vec<ImUser>>();
                        let is_end = im_users.len() != page_size;
                        let lasted_user = im_users.last();
                        let lasted : Option<ImUser> = match lasted_user {
                            None => {None}
                            Some(user) => {Some(user.clone())}
                        };
                        let user_service = ImUserService;
                        user_service.save_users(&mut im_users);
                        log::info!("load users success, and save success");

                        let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);
                        Timeout::new(100, move || {
                            pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                        }).forget();
                    }
                    Err(_) => {}
                }
            }
        });

        send_data(syn_data_config.app_state.clone(), RpcRequest::PullUsers(user_info_list_req), callback);
    }
}

pub fn syn_groups(syn_data_config: SynDataConfig<ImGroup>, pull_end_callback: PullEndCallback<ImGroup>) {
    let page_size : usize = 20;
    let start_server_id = match &syn_data_config.lasted_data {
        None => {None}
        Some(value) => {
            log::info!("syn group, start_user_id: {:?}", &value.server_id);
            value.server_id.clone()
        }
    };

    let websocket_status = syn_data_config.app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let group_info_list_req = GroupInfoListReq {
            group_type: GroupType::Chat,
            create_date_time: Local::now(),
            local_seq: "".to_string(),
            page_size,
            group_id: None,
            start_date: syn_data_config.start_time.clone(),
            start_server_id,
            session_id: None,
        };

        log::info!("begin load groups, {}", syn_data_config.app_state.receive_send_handle.is_some());

        let syn_data_config_clone = syn_data_config.clone();
        let pull_end_callback_clone = pull_end_callback.clone();

        let callback = Callback::from(move |response: RpcResponse| {
            let pull_end_callback_clone2 = pull_end_callback_clone.clone();
            let syn_data_config_clone2 = syn_data_config_clone.clone();
            
            if let RpcResponse::PullGroupsResponse(result) = response {
                match result {
                    Ok(group_info_item_list) => {
                        let mut im_groups = group_info_item_list.group_info_item_list.into_iter().map(|group_info_item| {group_info_item.into()}).collect::<Vec<ImGroup>>();
                        let is_end = im_groups.len() != page_size;
                        let lasted_group = im_groups.last();
                        let lasted : Option<ImGroup> = match lasted_group {
                            None => {None}
                            Some(group) => {Some(group.clone())}
                        };
                        let group_service = ImGroupService;
                        group_service.save_groups(&mut im_groups);
                        log::info!("load groups success, and save success, size: {}", im_groups.len());

                        let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);
                        Timeout::new(100, move || {
                            pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                        }).forget();
                    }
                    Err(_exception_resp) => {}
                }

            }

        });

        send_data(syn_data_config.app_state.clone(), RpcRequest::PullGroups(group_info_list_req), callback);
    }
}


pub fn syn_modules(syn_data_config: SynDataConfig<ImModule>, pull_end_callback: PullEndCallback<ImModule>) {
    let page_size : usize = 20;
    let start_server_name = match &syn_data_config.lasted_data {
        None => {None}
        Some(value) => {
            log::info!("syn module, start_server_name: {:?}", &value.name);
            Some(value.name.clone())
        }
    };

    let websocket_status = syn_data_config.app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let module_pull_req = ModulePullReq {
            page_size,
            start_date: syn_data_config.start_time.clone(),
            start_server_name,
            create_date_time: Default::default(),
            local_seq: "".to_string(),
        };

        log::info!("begin load modules, {}", syn_data_config.app_state.receive_send_handle.is_some());

        let syn_data_config_clone = syn_data_config.clone();
        let pull_end_callback_clone = pull_end_callback.clone();

        let callback = Callback::from(move |response: RpcResponse| {
            let pull_end_callback_clone2 = pull_end_callback_clone.clone();
            let syn_data_config_clone2 = syn_data_config_clone.clone();

            if let RpcResponse::PullModulesResponse(result) = response {
                match result {
                    Ok(module_info_item_list) => {
                        let mut im_modules = module_info_item_list.module_info_items.into_iter().map(|module_info_item| {module_info_item.into()}).collect::<Vec<ImModule>>();
                        let is_end = im_modules.len() != page_size;
                        let lasted_module = im_modules.last();
                        let lasted = match lasted_module {
                            None => {None}
                            Some(module) => {Some(module.clone())}
                        };
                        let module_service = ImModuleService;
                        module_service.save_modules(&mut im_modules);
                        log::info!("load module success, and save success, size: {}", im_modules.len());

                        let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);
                        Timeout::new(100, move || {
                            pull_end_callback_clone2.do_callback(new_syn_data_config);
                        }).forget();
                    }
                    Err(_exception_resp) => {}
                }

            }

        });

        send_data(syn_data_config.app_state.clone(), RpcRequest::PullModules(module_pull_req), callback);
    }
}


pub fn syn_sessions(syn_data_config: SynDataConfig<ImSession>, pull_end_callback: PullEndCallback<ImSession>) {
    let page_size : usize = 20;
    let start_server_id = match &syn_data_config.lasted_data {
        None => {None}
        Some(value) => {
            log::info!("syn session, start_server_name: {:?}", &value.name);
            Some(value.name.clone())
        }
    };

    let websocket_status = syn_data_config.app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let session_type = SessionType::Chat;
        let session_pull_req = SessionPullReq {
            page_size,
            start_date: syn_data_config.start_time.clone(),
            session_type,
            start_server_id,
            create_date_time: Default::default(),
            local_seq: "".to_string(),
        };

        log::info!("begin load session, {}", syn_data_config.app_state.receive_send_handle.is_some());

        let syn_data_config_clone = syn_data_config.clone();
        let pull_end_callback_clone = pull_end_callback.clone();

        let callback = Callback::from(move |response: RpcResponse| {
            let pull_end_callback_clone2 = pull_end_callback_clone.clone();
            let current_user_id = syn_data_config_clone.user_id.clone();
            let syn_data_config_clone2 = syn_data_config_clone.clone();

            if let RpcResponse::PullSessionsResponse(result) = response {
                match result {
                    Ok(session_item_list) => {
                        let mut im_sessions = session_item_list.session_item_list.into_iter()
                            .map(|session_item| ImSession::wrap(session_item, current_user_id.clone().to_string()))
                            .collect::<Vec<ImSession>>();

                        let is_end = im_sessions.len() != page_size;
                        let lasted_session = im_sessions.last();
                        let lasted = match lasted_session {
                            None => {None}
                            Some(session) => {Some(session.clone())}
                        };
                        let session_service = ImSessionService;
                        session_service.save_sessions(&mut im_sessions);
                        log::info!("load session success, and save success, size: {}", im_sessions.len());

                        let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);

                        Timeout::new(100, move || {
                            pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                        }).forget();
                    }
                    Err(_exception_resp) => {}
                }

            }

        });

        send_data(syn_data_config.app_state.clone(), RpcRequest::PullSessions(session_pull_req), callback);
    }
}


pub fn syn_messages(syn_data_config: SynDataConfig<MessageObject>, pull_end_callback: PullEndCallback<MessageObject>) {
    let page_size : usize = 200;
    let start_server_message_id = match &syn_data_config.lasted_data {
        None => {None}
        Some(value) => {
            log::info!("syn message, start_server_message_id: {:?}", &value.server_id);
            value.server_id.clone()
        }
    };

    let websocket_status = syn_data_config.app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let session_service = ImSessionService;
        let sessions = session_service.query("test00100", 0, 500);
        let session_ids = sessions.into_iter().map(|session| session.server_id.unwrap()).collect::<HashSet<String>>();
        let message_pull_req = MessagePullBySessionIdsReq {
            start_server_message_id,
            page_size,
            session_ids,
            terminal_type: TerminalType::Web,
            aft_date: syn_data_config.start_time.clone(),
        };

        log::info!("begin load message, {}", syn_data_config.app_state.receive_send_handle.is_some());

        let syn_data_config_clone = syn_data_config.clone();
        let pull_end_callback_clone = pull_end_callback.clone();

        let callback = Callback::from(move |response: RpcResponse| {
            let pull_end_callback_clone2 = pull_end_callback_clone.clone();
            let current_user_id = syn_data_config_clone.user_id.clone();
            let syn_data_config_clone2 = syn_data_config_clone.clone();

            if let RpcResponse::PullMessageBySessionIdsResponse(result) = response {
                match result {
                    Ok(message_object_list) => {
                        let message_objects = message_object_list.message_object_list;
                        log::info!("syn messages, {:?}", message_objects);

                        let size = message_objects.len();
                        let is_end = size != page_size;
                        let lasted_message = message_objects.last();
                        let lasted = match lasted_message {
                            None => {None}
                            Some(message) => {Some(message.clone())}
                        };
                        SaveMessageService::save_messages(current_user_id.clone(), message_objects, true);
                        log::info!("load message success, and save success, size: {}", size);


                        let new_syn_data_config = syn_data_config_clone2.copy2(lasted, is_end);

                        Timeout::new(100, move || {
                            pull_end_callback_clone2.do_callback(new_syn_data_config.clone());
                        }).forget();
                    }
                    Err(_) => {}
                }
            }
        });

        send_data(syn_data_config.app_state.clone(), RpcRequest::PullMessageBySessionIds(message_pull_req), callback);
    }
}



fn send_data(app_state: AppState, request: RpcRequest, callback: Callback<RpcResponse>) {
    let websocket_status = app_state.websocket_status.clone();

    if websocket_status == ImWebSocketStatus::Connected {
        let websocket_handle = app_state.receive_send_handle.clone();
        if let Some(websocket_handle) = websocket_handle {
            websocket_handle.dispatch(ImReceiveSendHandleMsg::Request(request, callback));
        } else {
            log::info!("no websocket handle");
        }
    }
}
